package com.kakarote.ids.provider.common;

import cn.hutool.core.util.StrUtil;
import com.kakarote.common.entity.UserInfo;
import com.kakarote.common.redis.Redis;
import com.kakarote.common.servlet.UserStrategy;
import com.kakarote.common.utils.UserUtil;
import com.kakarote.ids.provider.utils.UserCacheUtil;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@Aspect
@Component
public class UserAspect implements Ordered, UserStrategy {
  private static final Logger log = LoggerFactory.getLogger(UserAspect.class);
  
  @Autowired
  private Redis redis;
  
  private static final ThreadLocal<UserInfo> USER_THREAD_LOCAL = new ThreadLocal<>();
  
  @PostConstruct
  public void init() {
    UserUtil.setUserStrategy(this);
  }
  
  @Around("execution(@(org.springframework.web.bind.annotation.*Mapping) * *(..))")
  public Object around(ProceedingJoinPoint point) throws Throwable {
    ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
    try {
      if (attributes != null) {
        UserInfo info;
        HttpServletRequest request = attributes.getRequest();
        String token = request.getHeader("AUTH-TOKEN");
        if (StrUtil.isNotEmpty(token) && this.redis.exists(token)) {
          info = (UserInfo)this.redis.get(token);
        } else {
          info = (new UserInfo()).setUserId(Long.valueOf(0L));
        } 
        setUser(info);
      } 
      return point.proceed();
    } finally {
      removeUser();
    } 
  }
  
  public int getOrder() {
    return 1;
  }
  
  public UserInfo getUser() {
    return USER_THREAD_LOCAL.get();
  }
  
  public void setUser(UserInfo user) {
    USER_THREAD_LOCAL.set(user);
  }
  
  public void setUser(Long userId) {
    UserInfo userInfo = UserCacheUtil.getUserInfo(userId);
    setUser(userInfo);
  }
  
  public void removeUser() {
    USER_THREAD_LOCAL.remove();
  }
}
